package controller

import (
	"cloud-storage/global"
	"cloud-storage/lib"
	"cloud-storage/model/mysql"
	"cloud-storage/model/redis"
	"cloud-storage/pkg/encryption"
	"cloud-storage/pkg/jwt"
	"cloud-storage/utils"
	"cloud-storage/utils/response"
	"cloud-storage/utils/upload"
	"github.com/gin-gonic/gin"
	_redis "github.com/go-redis/redis/v8"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// SendSmsCode  发送短信验证码
func SendSmsCode(c *gin.Context) {
	//解析参数
	phone := c.Param("phone")
	//2.业务处理
	//通过验证码验证手机号的可用性
	code := utils.RandCode()
	/*err := message.SendSms(phone, code)
	if err != nil {
		zap.L().Error("sendSms failed", zap.Error(err))
		response.ResponseErrorWithMsg(c, response.CodeError, "验证码获取失败")
		return
	}*/

	//将code存入缓存中
	if err := redis.SetSms(code, phone); err != nil {
		zap.L().Error("redis.SetSms() failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeOperationFail)
		return
	}
	response.ResponseSuccess(c, nil)
}

// Register 注册
func Register(c *gin.Context) {
	//1.解析参数
	var p mysql.UserParam
	if err := c.ShouldBind(&p); err != nil {
		zap.L().Error("user c.ShouldBind() failed err: ", zap.Error(err))
		response.ResponseError(c, response.CodeParamIsInvalid)
		return
	}
	//进行比对，验证码一样，就说明输入信息正确，存入数据库中
	codeSms, err := redis.GetSms(p.Phone)
	if err != nil {
		zap.L().Error("GetSms failed:", zap.Error(err))
		response.ResponseError(c, response.CodeOperationFail)
		return
	}
	if p.Code == codeSms {
		//进行判断手机号是否已经注册过
		num, _err := mysql.GetPhone(&p)
		if _err != nil && _err != gorm.ErrRecordNotFound {
			zap.L().Error("user mysql.GetPhone() failed:", zap.Error(err))
			response.ResponseError(c, response.CodeSelectOperationFail)
			return
		}
		if num > 0 {
			response.ResponseError(c, response.CodeRegisterFail)
			return
		}
		err = mysql.CreateUser(&p)
		if err != nil {
			zap.L().Error("CreateUser failed:", zap.Error(err))
			response.ResponseError(c, response.CodeInsertOperationFail)
			return
		}
		response.ResponseSuccess(c, nil)
	} else {
		response.ResponseError(c, response.CodeLoginFailCode)
		return
	}
}

// LoginWithSms 登录，使用验证码验证进行登录
func LoginWithSms(c *gin.Context) {
	//解析参数
	var p mysql.UserParam
	if err := c.ShouldBind(&p); err != nil {
		zap.L().Error("user c.ShouldBind() failed err", zap.Error(err))
		response.ResponseError(c, response.CodeParamIsInvalid)
		return
	}
	//进行比对
	codeSms, err := redis.GetSms(p.Phone)
	if err != nil {
		zap.L().Error("user redis.GetSms() failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeSelectOperationFail)
		return
	}
	if p.Code == codeSms {
		//进行判断手机号是否已经注册过
		num, _err := mysql.GetPhone(&p)
		if _err != nil && _err != gorm.ErrRecordNotFound {
			zap.L().Error("user mysql.GetPhone() failed err:", zap.Error(err))
			response.ResponseError(c, response.CodeSelectOperationFail)
			return
		}
		if num > 0 {
			//手机号已经注册过,登录成功
			//生成token
			claim := jwt.CreateClaims(p.Phone)
			token, err := jwt.CreateToken(claim)
			if err != nil {
				zap.L().Error("user jwt.CreateToken() failed err:", zap.Error(err))
				response.ResponseError(c, response.CodeInvalidToken)
				return
			}
			if lib.AppSetting.UseMultipoint {
				response.ResponseSuccess(c, token)
				return
			}
			//判断是否登录成功
			err = jwt.SetToken(token, claim)
			if err != nil {
				response.ResponseError(c, response.CodeLoginFailReLogin)
				return
			}
			response.ResponseSuccess(c, token)
		} else {
			response.ResponseError(c, response.CodeLoginFailResCode)
			return
		}
	}
}

// LoginWithPassword 使用密码登录
func LoginWithPassword(c *gin.Context) {
	//解析参数
	var p mysql.UserParam
	if err := c.ShouldBind(&p); err != nil {
		response.ResponseError(c, response.CodeParamIsInvalid)
		return
	}
	//根据手机号去查询密码
	password, err := mysql.GetPassword(&p)
	if err != nil {
		zap.L().Error("GetPassword failed:", zap.Error(err))
		return
	}
	//判断密码是否正确
	err = encryption.BcryptCheck(p.Password, password)
	if err != nil {
		response.ResponseErrorWithMsg(c, response.CodeError, "手机号或密码错误")
		return
	}

	//添加token
	claim := jwt.CreateClaims(p.Phone)
	token, err := jwt.CreateToken(claim)
	if err != nil {
		zap.L().Error("CreateToken failed:", zap.Error(err))
		response.ResponseErrorWithMsg(c, response.CodeError, "获取token失败")
		return
	}
	if lib.AppSetting.UseMultipoint {
		response.ResponseSuccess(c, token)
		return
	}
	//判断是否登录成功
	err = jwt.SetToken(token, claim)
	if err != nil {
		response.ResponseError(c, response.CodeLoginFailReLogin)
		return
	}
	response.ResponseSuccess(c, token)
}

// UpdatePassword 登录成功后设置密码,需要验证码进行验证
func UpdatePassword(c *gin.Context) {
	//解析参数
	var p mysql.UserParam
	if err := c.ShouldBind(&p); err != nil {
		zap.L().Error("user c.ShouldBind() failed err", zap.Error(err))
		response.ResponseError(c, response.CodeParamIsInvalid)
		return
	}
	//进行比对
	codeSms, err := redis.GetSms(p.Phone)
	if err != nil {
		zap.L().Error("GetSms failed:", zap.Error(err))
		response.ResponseError(c, response.CodeSelectOperationFail)
		return
	}
	if p.Code == codeSms {
		//短信验证码通过,将密码写进数据库
		//1. 先对密码进行加密
		p.Password = encryption.BcryptHash(p.Password)
		//2.将密码写进数据库中
		err = mysql.UpdatePassword(&p)
		if err != nil {
			zap.L().Error("update failed err:", zap.Error(err))
			response.ResponseError(c, response.CodeUpdateOperationFail)
			return
		}
		response.ResponseSuccess(c, nil)
	} else {
		response.ResponseError(c, response.CodeLoginFailCode)
		return
	}

}

// UpdateName 更新用户名
func UpdateName(c *gin.Context) {
	//1. 解析参数
	userName := c.Query("name")
	//处理业务
	err := mysql.UpdateName(userName, global.GetPhone(c))
	if err != nil {
		zap.L().Error("user mysql.UpdateName() Failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeUpdateOperationFail)
		return
	}
	response.ResponseSuccess(c, nil)
}

// UpdateImage 设置头像,将图片保存在本地并将图片地址保存进数据库中
func UpdateImage(c *gin.Context) {
	_, header, err := c.Request.FormFile("image")
	if err != nil {
		zap.L().Error("user c.Request.FormFile failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeFileLoadingFail)
		return
	}
	//上传到本地
	imagePath, err := upload.UploadFile(header, lib.ImagesSetting.ImagePath)
	if err != nil {
		zap.L().Error("user upload.UploadFile() failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeFileUploadFail)
		return
	}
	//将路径存入数据库中
	err = mysql.UpdateImage(imagePath, global.GetPhone(c))
	if err != nil {
		zap.L().Error("mysql.UpdateImage() failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeUpdateOperationFail)
		return
	}
	//判断redis中是否已经存在key，存在直接删除key
	_, err = redis.GetImage(global.GetPhone(c))
	if err == _redis.Nil || err == nil {
		//删除key
		err = redis.DelKey(global.GetPhone(c))
		if err != nil {
			zap.L().Error("redis.DelKey() failed err:", zap.Error(err))
			response.ResponseError(c, response.CodeOperationFail)
			return
		}
		response.ResponseSuccess(c, imagePath)
	} else {
		zap.L().Error("redis.GetImage() failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeFileUploadFail)
		return
	}

}

// GetImage 获取头像
func GetImage(c *gin.Context) {
	//先判断redis中是否存在
	image, err := redis.GetImage(global.GetPhone(c))
	if err != nil && err == _redis.Nil {
		//redis中不存在，查找数据库
		images, err := mysql.GetImage(global.GetPhone(c))
		if err != nil {
			zap.L().Error("user mysql.GetImage() failed err:", zap.Error(err))
			response.ResponseError(c, response.CodeSelectOperationFail)
			return
		}
		//将查到的image放如缓存中
		err = redis.SetImage(image, global.GetPhone(c))
		if err != nil {
			zap.L().Error("user redis.SetImage() failed err:", zap.Error(err))
			response.ResponseError(c, response.CodeOperationFail)
			return
		}
		response.ResponseSuccess(c, images)
	} else if err != nil {
		zap.L().Error("user redis.GetImage() failed err:", zap.Error(err))
		response.ResponseError(c, response.CodeSelectOperationFail)
		return
	} else {
		response.ResponseSuccess(c, image)
	}
}
